
/**
 * ast生成渲染函数
 * @param {*} ast ast语法树
 * @returns 渲染函数
 */
export function generate(ast) {
  // 渲染函数字符串形式
  const renderStr = genElement(ast)
  // 通过new Function 将字符串实行的函数变成可执行函数，并用with为渲染函数扩展作用域链
  return new Function(`with(this){return ${renderStr}}`)
}

/**
 * 解析ast,生成 渲染函数
 * @param {*} ast ast语法树
 * @returns 渲染函数的字符串形式
 */
function genElement(ast) {
  // 取出标签，属性的kv形式的集合，一些动态属性
  const { tag, rawAttr, attr } = ast
  // 生成属性Map对象，静态属性 + 动态属性
  const attrs = { ...rawAttr, ...attr }
  // 处理子节点，得到一个所有子节点渲染函数组成的数组
  const children = genChildren(ast)
  if (tag === 'slot') {
    // 生成插槽处理函数
    return `_t(${JSON.stringify(attrs)}, [${children}])`
  }
  // 生成 VNode 的可执行方法
  const fnStr = `_c('${tag}', ${JSON.stringify(attrs)}, [${children}])`
  return fnStr
}

/**
 * 处理ast 节点的子节点，将子节点变为渲染函数
 * @param {*} ast 节点的ast对象
 * @returns [childNodeRender1, ...]
 */
function genChildren(ast) {
  const ret = [],
  { children } = ast
  // 遍历所有的子节点
  for(let i =0; i < children.length; i++) {
    const child = children[i]
    if (child.type === 3) {
      // 文本节点
      ret.push(`_v(${JSON.stringify(child)})`)
    } else if (child.type === 1) {
      ret.push(genElement(child))
    }
  }
  return ret
}